#include "StringParser.h"
#include "WONCommon/LittleEndian.h"

using namespace std;
using namespace WONAPI;
using namespace WONTypes;

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
unsigned char StringParser::GetChar(int theOffset)
{
	if(mIsWString)
	{
		wchar_t aWChar = ((wchar_t*)mStr)[mPos+theOffset];
		if(aWChar >= 256)
			return (unsigned char)255;
		else
			return (unsigned char)aWChar;
	}
	else
		return mStr[mPos+theOffset];
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::IncrementPos(int theAmount)
{
	mPos += theAmount;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
wchar_t StringParser::GetWChar(int theOffset)
{
	if(mIsWString)
		return ((wchar_t*)mStr)[mPos+theOffset];
	else
		return (unsigned char)mStr[mPos+theOffset];
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::EndOfString()
{
	if(mIsWString)
		return *(((wchar_t*)mStr)+mPos)==L'\0';
	else
		return mStr[mPos]=='\0';
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::StartsWith(const char *theStr)
{
	int originalPos = mPos;
	const unsigned char *p = (const unsigned char*)theStr;
	while(*p!='\0' && !EndOfString())
	{
		if(*p!=GetChar())
		{
			mPos = originalPos;
			return false;
		}

		p++;
		mPos++;
	}

	if(EndOfString() && *p!='\0')
	{
		mPos = originalPos;
		return false;
	}

	return true;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::Is(const char *theStr)
{
	bool startsWith = StartsWith(theStr);
	return startsWith && EndOfString();
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::SkipWhitespace()
{
	while(!EndOfString() && isspace(GetChar()))
		mPos++;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::SkipNonWhitespace()
{
	while(!EndOfString() && !isspace(GetChar()))
		mPos++;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::CheckNextChar(int theChar)
{
	SkipWhitespace();
	if(theChar==GetChar())
	{
		mPos++;
		return true;
	}
	else
		return false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static int CharToHex(char theChar)
{
	if(isdigit(theChar))
		return theChar - '0';
	else
		return toupper(theChar) - 'A' + 10;

}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void AppendWChar(wstring &theStr, wchar_t theChar)
{
	theStr += theChar;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void AppendWChar(string &theStr, wchar_t theChar)
{
	unsigned short aTwoBytes = (unsigned short)theChar;
	aTwoBytes = ShortToLittleEndian(aTwoBytes);
	theStr.append((char*)&aTwoBytes,2);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void AppendChar(wstring &theStr, char theChar)
{
	theStr += (wchar_t)theChar;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void AppendChar(string &theStr, char theChar)
{
	theStr += theChar;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template <class T>
static bool TemplateReadString(StringParser *theParser, T &theStr, bool theStrIsWString, bool stopAtWhitespace)
{
	theStr.erase();
	theParser->SkipWhitespace();
	bool inQuote = false;
	bool isWString = theStrIsWString;
	wchar_t aWideChar;
	unsigned char aChar;
	int aLastNonSpaceSize = 0;

	while(!theParser->EndOfString())
	{
		aChar = theParser->GetChar();
		if(isWString)
			aWideChar = theParser->GetWChar();

		theParser->IncrementPos();

		if(stopAtWhitespace && isspace(aChar) && !inQuote)
			break;
			
		if(aChar=='\\' && inQuote)
		{
			unsigned char anotherChar = theParser->GetChar();
			theParser->IncrementPos();

			switch(anotherChar)
			{
				case 't': aWideChar = L'\t'; break;
				case 'n': aWideChar = L'\n'; break;
				case 'r': aWideChar = L'\r'; break;
				case '"': aWideChar = L'\"'; break;
				case '\\': aWideChar = L'\\'; break;
				case '$': aWideChar = L'$'; break;
				case 'x':
				{
					int aNumTimes = isWString ? 4 : 2;
					aWideChar = 0;
					for(int i=0; i<aNumTimes; i++)
					{
						if(isxdigit(theParser->GetChar()))
						{
							aWideChar <<= 4;
							aWideChar |= CharToHex(theParser->GetChar());
							theParser->IncrementPos();
						}
						else
							break;
					}
					break;
				}
				default: // not a special escape sequence
					theParser->IncrementPos(-1);
					aWideChar = L'\\';
			}

			if(isWString)
				AppendWChar(theStr,aWideChar);
			else
				AppendChar(theStr,(char)aWideChar);

			aLastNonSpaceSize = theStr.size();
		}
		else if(!inQuote && aChar=='L' && theParser->GetChar()=='"')
		{
			theParser->IncrementPos();
			isWString = true;
			inQuote = true;
		}
		else if(aChar=='"')
		{
			if(inQuote)
			{
				inQuote = false;
				if(theParser->GetChar()=='+')
				{
					theParser->IncrementPos();
					theParser->SkipWhitespace();
					continue;
				}
				else
					break;
			}
			else
			{
				if(!theStrIsWString)
					isWString = false;

				inQuote = true;
			}
		}
		else if(!inQuote && (aChar==',' || aChar==')')) // , and ) are special characters used to read lists
		{
			theParser->IncrementPos(-1);
			break;
		}
		else
		{
			if(isWString)
				AppendWChar(theStr,aWideChar);
			else
				AppendChar(theStr,aChar);

			if(inQuote || !isspace(aChar))
				aLastNonSpaceSize = theStr.size();
		}
	}

	theStr.resize(aLastNonSpaceSize);
	return true;
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(std::string &theStr, bool stopAtWhitespace)
{
	return TemplateReadString<string>(this,theStr,false,stopAtWhitespace);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(std::wstring &theStr, bool stopAtWhitespace)
{
	return TemplateReadString<wstring>(this,theStr,true,stopAtWhitespace);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template<class IntType>
static bool StringParser_ReadInt(StringParser *theParser, IntType &theInt)
{
	theParser->SkipWhitespace();
	int aNum = 0;
	int originalPos = theParser->GetPos();

	bool isNegative = false;
	if(theParser->GetChar()=='-')
	{
		isNegative = true;
		theParser->IncrementPos();
	}

	if(theParser->GetChar(0)=='0' && tolower(theParser->GetChar(1))=='x') // hex
	{
		theParser->IncrementPos(2);
		while(isxdigit(theParser->GetChar()))
		{
			aNum*=16;
			char aChar = toupper(theParser->GetChar());
			if(aChar>='0' && aChar<='9')
				aNum += aChar - '0';
			else if(aChar>='A' && aChar<='F')
				aNum += aChar - 'A' + 10;
			else
				break;

			theParser->IncrementPos();
		}
	}
	else // decimal
	{
		while(isdigit(theParser->GetChar()))
		{
			aNum*=10;
			aNum += theParser->GetChar() - '0';
			theParser->IncrementPos();
		}
	}

	if(isNegative)
		aNum*=-1;

	if(theParser->GetPos()!=originalPos)
	{
		theInt = aNum;
		return true;
	}
	else
		return false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(__int64 &theInt64)
{
	return StringParser_ReadInt(this,theInt64);
}	

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(int &theInt)
{
	return StringParser_ReadInt(this,theInt);
}	

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(bool &theBool)
{
	SkipWhitespace();
	string aStr;
	while(!EndOfString())
	{
		char aChar = toupper(GetChar());

		if(!isalnum(aChar))
			break;
		else 
			aStr += aChar;

		mPos++;
	}

	if(aStr=="TRUE" || aStr=="YES" || aStr=="ON" || aStr=="Y" || aStr=="T" || aStr=="1")
		theBool = true;
	else if(aStr=="FALSE" || aStr=="NO" || aStr=="OFF" || aStr=="N" || aStr=="F" || aStr=="0")
		theBool = false;
	else
		return false;

	return true;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template<class T> 
static bool ReadList(StringParser *theParser, std::list<T> &theList)
{
	while(true)
	{
		theList.push_back(T());
		if(!theParser->ReadValue(theList.back()))
		{
			theList.pop_back();
			return false;
		}
		
		if(!theParser->CheckNextChar(','))
			break;
	}

	return true;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(BoolList &theList)
{
	return ReadList<bool>(this,theList);
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(IntList &theList)
{
	return ReadList<int>(this,theList);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(StringList &theList)
{
	return ReadList<string>(this,theList);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(WStringList &theList)
{
	return ReadList<wstring>(this,theList);
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template<class T>
static bool ReadListList(StringParser *theParser, std::list<std::list<T> > &theList)
{
	while(true)
	{
		if(!theParser->CheckNextChar('('))
			break;

		theList.push_back(std::list<T>());
		if(!ReadList<T>(theParser,theList.back()))
			return false;

		if(!theParser->CheckNextChar(')'))
			return false;

		if(!theParser->CheckNextChar(','))
			break;
	}

	return true;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(BoolListList &theList)
{
	return ReadListList<bool>(this,theList);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(IntListList &theList)
{
	return ReadListList<int>(this,theList);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(StringListList &theList)
{
	return ReadListList<string>(this,theList);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool StringParser::ReadValue(WStringListList &theList)
{
	return ReadListList<wstring>(this,theList);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const bool &theBool, std::string &theStr)
{
	if(theBool)
		theStr += "True";
	else
		theStr += "False";
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const int &theVal, std::string &theStr)
{
	ValueToString((long&)theVal, theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const unsigned __int64 &theInt64, std::string &theStr)
{
	char aBuf[50];
	sprintf(aBuf,"%I64u",theInt64);
	theStr += aBuf;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const __int64 &theInt64, std::string &theStr)
{
	char aBuf[50];
	sprintf(aBuf,"%I64d",theInt64);
	theStr += aBuf;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const unsigned long &theLong, std::string &theStr)
{
	char aBuf[50];
	sprintf(aBuf,"%u",theLong);
	theStr += aBuf;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const long &theLong, std::string &theStr)
{
	char aBuf[50];
	sprintf(aBuf,"%d",theLong);
	theStr += aBuf;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const short &theShort, std::string &theStr)
{
	long aLong = theShort;
	ValueToString(aLong, theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const unsigned short &theShort, std::string &theStr)
{
	long aLong = theShort;
	ValueToString(aLong, theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const char &theByte, std::string &theStr)
{
	long aLong = theByte;
	ValueToString(aLong, theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const unsigned char &theByte, std::string &theStr)
{
	unsigned long aLong = theByte;
	ValueToString(aLong, theStr);
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const std::string &theVal, std::string &theStr)
{
	theStr += theVal;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const std::wstring &theVal, std::string &theStr)
{
	theStr += WStringToString(theVal);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template <class T> 
static void ListToString(const std::list<T> &theList, string &theStr)
{
	std::list<T>::const_iterator anItr = theList.begin();
	while(anItr!=theList.end())
	{
		StringParser::ValueToString(*anItr,theStr);
		++anItr;
		if(anItr!=theList.end())
			theStr += ", ";

	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const BoolList &theVal, std::string &theStr)
{
	ListToString<bool>(theVal,theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const IntList &theVal, std::string &theStr)
{
	ListToString<int>(theVal,theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const StringList &theVal, std::string &theStr)
{
	ListToString<string>(theVal,theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const WStringList &theVal, std::string &theStr)
{
	ListToString<wstring>(theVal,theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template <class T> 
static void ListListToString(const std::list<std::list<T> > &theList, string &theStr)
{
	std::list<std::list<T> >::const_iterator anItr = theList.begin();
	while(anItr!=theList.end())
	{
		theStr += "(";
		ListToString<T>(*anItr,theStr);
		theStr +=")";
		++anItr;
		if(anItr!=theList.end())
			theStr += ", ";

	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const WONTypes::BoolListList &theVal, std::string &theStr)
{
	ListListToString<bool>(theVal, theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const WONTypes::IntListList &theVal, std::string &theStr)
{
	ListListToString<int>(theVal, theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const WONTypes::StringListList &theVal, std::string &theStr)
{
	ListListToString<string>(theVal,theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void StringParser::ValueToString(const WONTypes::WStringListList &theVal, std::string &theStr)
{
	ListListToString<wstring>(theVal,theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
